﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ZZMES.TCP
{
    /// <summary>
    /// 接收Socket的操作
    /// </summary>
    public enum EnsocketAction
    {
        /// <summary>连接</summary>
        Connect = 1,
        /// <summary>发送数据</summary>
        SendMsg = 2,
        /// <summary>关闭</summary>
        Close = 3
    }
    public class MyTCPServer
    {
        private TcpListener listener;


        /// <summary>标识是否接受客户端连接</summary>
        private ManualResetEvent doConnect = new ManualResetEvent(false);
        /// <summary>标识是否接收数据</summary>
        private ManualResetEvent doReceive = new ManualResetEvent(false);
        /// <summary>标识服务器是否关闭</summary>
        public bool IsClose = false;

        /// <summary>已连接的客户端</summary>
        public Dictionary<string, TcpClient> clients = new Dictionary<string, TcpClient>();

        /// <summary>连接发送关闭事件</summary>
        public event Action<string, EnsocketAction> CompletedEvent;
        /// <summary>接收数据事件</summary>
        public event Action<string, string> ReceivedEvent;

        /// <summary>
        /// 建立服务器并开启监听
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        public void BuildServer(string ip, int port)
        {
            IsClose = false;
            listener = new TcpListener(new IPEndPoint(IPAddress.Parse(ip), port));
            //开始监听
            listener.Start();
            ThreadPool.QueueUserWorkItem(x =>
            {
                while (!IsClose)
                {
                    doConnect.Reset();
                    listener.BeginAcceptTcpClient(AcceptCallBack, listener);
                    doConnect.WaitOne();
                }
            });
        }

        /// <summary>
        /// 接收连接回调函数
        /// </summary>
        /// <param name="ar"></param>
        private void AcceptCallBack(IAsyncResult ar)
        {
            TcpListener tcpListener = ar.AsyncState as TcpListener;
            TcpClient tcpClient = tcpListener.EndAcceptTcpClient(ar);
            doConnect.Set();
            //获取请求连接客户端的IP信息
            IPEndPoint iPEndPoint = tcpClient.Client.RemoteEndPoint as IPEndPoint;
            string Key = string.Format("{0}:{1}", iPEndPoint.Address.ToString(), iPEndPoint.Port);
            //添加到已连接客户端字典
            if (!clients.ContainsKey(Key))
            {
                clients.Add(Key, tcpClient);
                OnComplete(Key, EnsocketAction.Connect);
            }
        }

        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="key">要发送客户端的客户端IP端口（192.168.1.1:2000）</param>
        /// <param name="msg">信息</param>
        public void Send(string key, string msg)
        {
            if (!clients.ContainsKey(key))
            {
                throw new Exception("未检测到该客户端已连接上服务器");
            }
            TcpClient client = clients[key];
            byte[] listData = Encoding.UTF8.GetBytes(msg);
            client.Client.BeginSend(listData, 0, listData.Length, SocketFlags.None, SendCallBack, client);
        }

        /// <summary>
        /// 向所有已连接的客户端发送数据
        /// </summary>
        /// <param name="msg"></param>
        public void Send(string msg)
        {
            foreach (var c in clients.Values)
            {
                try
                {
                    TcpClient client = c;
                    byte[] listData = Encoding.UTF8.GetBytes(msg);
                    client.Client.BeginSend(listData, 0, listData.Length, SocketFlags.None, SendCallBack, client);
                }
                catch
                {
                    continue;
                }

            }

        }

        /// <summary>
        /// 发送数据回调函数
        /// </summary>
        /// <param name="ar"></param>
        private void SendCallBack(IAsyncResult ar)
        {
            TcpClient client = ar.AsyncState as TcpClient;
            //获取要发送给的客户端IP信息
            IPEndPoint iPEndPoint = client.Client.RemoteEndPoint as IPEndPoint;
            string Key = string.Format("{0}:{1}", iPEndPoint.Address.ToString(), iPEndPoint.Port);
            //发送
            if (CompletedEvent != null)
            {
                CompletedEvent(Key, EnsocketAction.SendMsg);
            }
        }

        /// <summary>
        /// 接收数据
        /// </summary>
        /// <param name="key"></param>
        private void ReceiveData(string key)
        {
            doReceive.Reset();
            if (clients.ContainsKey(key))
            {
                TcpClient tcpClient = clients[key];
                StateObject obj = new StateObject();
                obj.Client = tcpClient;
                try
                {
                    tcpClient.Client.BeginReceive(obj.ReceiveData, 0, obj.ReceiveData.Length, SocketFlags.None, ReceiveCallBack, obj);
                }
                catch { }
                doReceive.WaitOne();
            }
        }

        /// <summary>
        /// 接收数据回调函数
        /// </summary>
        /// <param name="ar"></param>
        private void ReceiveCallBack(IAsyncResult ar)
        {
            try
            {
                StateObject obj = ar.AsyncState as StateObject;
                //接收到的数据长度
                int count = obj.Client.Client.EndReceive(ar);
                doReceive.Set();
                if (count > 0)
                {
                    string msg = Encoding.UTF8.GetString(obj.ReceiveData, 0, count);
                    if (!string.IsNullOrEmpty(msg))
                    {
                        if (ReceivedEvent != null)
                        {
                            //获取发送信息的客户端IP信息
                            IPEndPoint iPEndPoint = obj.Client.Client.RemoteEndPoint as IPEndPoint;
                            string Key = string.Format("{0}:{1}", iPEndPoint.Address.ToString(), iPEndPoint.Port);
                            //触发接收数据事件
                            ReceivedEvent(Key, msg);
                        }
                    }
                }
            }
            catch { }

        }

        /// <summary>
        /// 连接发送等事件
        /// </summary>
        /// <param name="key"></param>
        /// <param name="enAction"></param>
        public virtual void OnComplete(string key, EnsocketAction enAction)
        {
            if (CompletedEvent != null)
                CompletedEvent(key, enAction);
            //当客户端连接建立时，开启监听数据接收
            if (enAction == EnsocketAction.Connect)
            {
                ThreadPool.QueueUserWorkItem(x =>
                {
                    while (clients.ContainsKey(key) && !IsClose)
                    {
                        //前后需要加一点延迟
                        Thread.Sleep(20);
                        ReceiveData(key);
                        Thread.Sleep(20);
                    }
                });
            }
            if (enAction == EnsocketAction.Close)
            {
                clients.Remove(key);
            }
        }

        /// <summary>
        /// 关闭连接
        /// </summary>
        public void Close()
        {
            IsClose = true;
        }

    }
}
